package com.coder.rental.security;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.convert.NumberWithFormat;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWTPayload;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.coder.rental.entity.User;
import com.coder.rental.utils.JwtUtils;
import com.coder.rental.utils.RedisUtils;
import com.coder.rental.utils.ResultCode;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

// 登录成功处理类
// 该类实现了AuthenticationSuccessHandler接口，用于处理用户成功认证后的逻辑
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    @Resource
    private RedisUtils redisUtils;
    /**
     * 处理登录成功的方法
     * 当用户成功认证后，Spring Security会调用此方法来处理登录成功的逻辑
     *
     * @param request  HttpServletRequest对象，用于获取请求信息
     * @param response HttpServletResponse对象，用于设置响应信息
     * @param authentication 认证对象，包含用户信息和权限信息
     * @throws IOException 当输出流操作失败时抛出
     * @throws ServletException 当处理过程中发生Servlet相关的错误时抛出
     */
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        // 设置客户端的响应的内容类型是json
        response.setContentType("application/json;charset=UTF-8");
        // 获取用户信息
        User user = (User) authentication.getPrincipal();
        // 生成token的处理
        // 创建一个HashMap实例，用于存储用户信息
        Map<String,Object> map = new HashMap<>();
        // 将用户的用户名存入map中
        map.put("username",user.getUsername());
        // 将用户的ID存入map中
        map.put("userid",user.getId());
        // 调用JwtUtils.createToken方法，根据map中的用户信息创建一个JWT令牌
        String token = JwtUtils.createToken(map);
        // 从JWT令牌中解析出过期时间的声明
        NumberWithFormat claim = (NumberWithFormat) JwtUtils.parseToken(token).getClaim(JWTPayload.EXPIRES_AT);
        // 将过期时间声明转换为日期，并获取其时间戳
        long expireTime = Convert.toDate(claim).getTime();
        // 创建一个AuthenticationResult实例，包含用户ID、成功的结果代码、JWT令牌和过期时间
        AuthenticationResult authenticationResult =
                new AuthenticationResult(user.getId(),
                        ResultCode.SUCCESS,token,expireTime);

        // 获取一个结果
        String result = JSON.toJSONString(authenticationResult, SerializerFeature.DisableCircularReferenceDetect);

        // 获取输出流
        ServletOutputStream outputStream = response.getOutputStream();
        // 将用户信息的JSON字符串写入输出流
        outputStream.write(result.getBytes(StandardCharsets.UTF_8));
        // 刷新输出流，确保数据被发送
        outputStream.flush();
        // 关闭输出流
        outputStream.close();
        //把token存到redis中，设置过期时间
        String tokenKey = "token:"+token;
        long newTime = DateTime.now().getTime();
        redisUtils.set(tokenKey,token,(expireTime-newTime)/1000);
    }
}
